#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#include <error.h>
#include <pthread.h>

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
#include <libswresample/swresample.h>

#define MAX_AUDIO_FRAME_SIZE 192000
#define BUFF_LEN 4 * 1024
#define PORT 1077

#define BUF_SIZE 4096*500

int conn_fd;
void process_client();
int find_byte_in_arr(char arr[], size_t search_begin, size_t search_length, char c);

/**
 * 接受adas设备码流并解析为pcm
 */
int main()
{
    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(struct sockaddr_in)); //清零
    server_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
    server_addr.sin_port = htons(PORT);
    server_addr.sin_family = AF_INET;

    //绑定地址结构到套接字描述符
    if (bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        perror("bind error\n");
        return -1;
    }

    if (listen(listen_fd, 20) < -1)
    {
        perror("listen error\n");
    }

    while (1)
    { //接受客户端连接
        socklen_t addrlen = sizeof(struct sockaddr);
        struct sockaddr_in clientaddr; //客户端地址结构

        conn_fd = accept(listen_fd, (struct sockaddr *)&clientaddr, &addrlen);

        if (conn_fd < 0)
        {
            perror("accept error");
            return -1;
        }
        printf("accept success\n");

        pthread_t pid;

        if (pthread_create(&pid, NULL, process_client, NULL) < 0)
        {
            printf("pthread create error\n");
        }
    }
    close(listen_fd);
}

int print_char_arr(char arr[])
{
    for (size_t i = 0; i < sizeof(arr); i++)
    {
        if (arr[i] == '\0')
        {
            printf("\n");
            break;
        }
        else
        {
            printf("%x", arr[i]);
        }
    }
}
// 从arr数组里面查找c，从search_begin开始查找search_length个char
int find_byte_in_arr(char arr[], size_t search_begin, size_t search_length, char c)
{
    if (search_begin == -1)
        search_begin = 0;
    for (size_t i = search_begin; i < search_begin + search_length; i++)
    {
        if (arr[i] == '\0')
        {
            //\0表示EOF，需要返回
            return -1;
        }
        if (arr[i] == c)
        {
            return i;
        }
    }
    return -1;
}

//数组copy，从src往dest复制len个char数据
int copy_byte_arr(char src[], char dest[], size_t src_index, size_t dest_index, size_t len)
{
    for (size_t i = 0; i < len; i++)
    {
        dest[dest_index + i] = src[src_index + i];
    }
}

int find_chars_in_arr(char src[], char target[], size_t src_start)
{
    for (size_t i = src_start; i < sizeof(src); i++)
    {
        for (size_t num = 0; num < 4; num++)
        {
            if (src[i + num] != target[num])
                break;
            if (num == 3)
                return i;
        }
    }
    return -1;
}

void process_client()
{
    //注册所有的工具
    av_register_all();

    AVFormatContext *fmt_ctx = NULL;
    AVCodecContext *cod_ctx = NULL;
    AVCodec *cod = NULL;
    printf("step 2 ...........................\n");
    //分配一个avformat
    fmt_ctx = avformat_alloc_context();
    if (fmt_ctx == NULL)
        printf("alloc fail");

    printf("step 3 ...........................\n");

    cod = avcodec_find_decoder(AV_CODEC_ID_AAC);
    cod_ctx = avcodec_alloc_context3(cod);

    if (avcodec_open2(cod_ctx, cod, NULL) < 0)
        printf("can't open codec");

    //创建packet,用于存储解码前的数据
    AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));

    //设置转码后输出相关参数
    //采样的布局方式
    uint64_t out_channel_layout = AV_CH_LAYOUT_MONO;
    //采样个数
    int out_nb_samples = 1024;
    //采样格式
    enum AVSampleFormat sample_fmt = AV_SAMPLE_FMT_S16;
    //采样率
    int out_sample_rate = 44100;
    //通道数
    int out_channels = av_get_channel_layout_nb_channels(out_channel_layout);
    printf("%d\n", out_channels);
    //创建buffer
    int buffer_size = av_samples_get_buffer_size(NULL, out_channels, out_nb_samples, sample_fmt, 1);

    //注意要用av_malloc
    uint8_t *buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE * 2);

    //创建Frame，用于存储解码后的数据
    AVFrame *frame = av_frame_alloc();

    int got_picture;

    int64_t in_channel_layout = av_get_default_channel_layout(1);
    //打开转码器
    struct SwrContext *convert_ctx = swr_alloc();
    //设置转码参数
    convert_ctx = swr_alloc_set_opts(convert_ctx, out_channel_layout, sample_fmt, out_sample_rate,
                                     in_channel_layout, cod_ctx->sample_fmt, cod_ctx->sample_rate, 0, NULL);
    //初始化转码器
    swr_init(convert_ctx);

    //每次读取一帧，并转码,这里接受webscoket的数据
    av_init_packet(packet);

    // ========================================prepare end ========================================

    int client_socket_fd = conn_fd;
    int size = 0;

    int prev_index = -1;
    //单次socket read的buff
    char buff[BUFF_LEN];

    char rtp_head[4] = {0x30, 0x31, 0x63, 0x64};
    char rtp_buff[24 * 1024];
    int rtp_buff_write_index;
    int remain_to_read;
    int is_complete;
    while (1)
    {
        memset(buff, 0, BUFF_LEN);
        size = read(client_socket_fd, buff, BUFF_LEN);

        //先查找7e开头的字节，标记为starPos
        if (size > 0)
        {
            int index_count;
            int arr[5];
            size_t i;
            if (remain_to_read != 0)
            {
                copy_byte_arr(buff, rtp_buff, 0, rtp_buff_write_index, remain_to_read);
                rtp_buff_write_index += remain_to_read;
            }
            for (i = 0; i < sizeof(buff); i++)
            {
                if (buff[i] == 0x30 && buff[i + 1] == 0x31 && buff[i + 2] == 0x63 && buff[i + 3] == 0x64)
                {
                    is_complete = buff[i + 5] >> 7;
                    if (is_complete)
                    {
                        printf("complete flag, index is %d\n", i);
                    }
                    arr[++index_count] = i;
                    //说明拿到了头数据，那么后面需要读取的字节也就明白了
                    int body_len = (buff[i + 28] & 0xff) << 8 | ((buff[i + 29] & 0xff));
                    printf("body length is : %d\n", body_len);

                    //从i+29开始需要读取950字节的数据
                    if (size > i + 29 + body_len)
                    {
                        copy_byte_arr(buff, rtp_buff, i + 29, rtp_buff_write_index, body_len);
                        rtp_buff_write_index += body_len;
                    }
                    else
                    {
                        copy_byte_arr(buff, rtp_buff, i + 29, rtp_buff_write_index, size - (i + 29));
                        remain_to_read = body_len - (size - (i + 29));
                        break;
                    }
                }
            }

            //avioContext probe start
            AVIOContext *pb = NULL;
            AVInputFormat *piFmt = NULL;
            AVInputFormat *pFmt = NULL;

            uint8_t *buf = (uint8_t *)av_mallocz(sizeof(uint8_t) * BUF_SIZE);
            copy_byte_arr(rtp_buff,buf,0,0,size);
            
            pb = avio_alloc_context(buf, BUF_SIZE, 0, NULL, NULL, NULL, NULL);
            if (av_probe_input_buffer(pb, &piFmt, "", NULL, 0, 0) < 0) //探测从内存中获取到的媒体流的格式
            {
                fprintf(stderr, "probe format failed\n");
                return -1;
            }
            else
            {
                fprintf(stdout, "format:%s[%s]\n", piFmt->name, piFmt->long_name);
            }
            //avioContext probe end
            // =========================================decode ==============================

            //初始化工作完成，开启socket，准备解析数据
            av_packet_from_data(packet, rtp_buff, size);
            //解码声音
            if (avcodec_decode_audio4(cod_ctx, frame, &got_picture, packet) < 0)
            {
                perror("decode error");
                close(client_socket_fd);
                //return -1;
            }

            if (got_picture > 0)
            {
                //转码
                swr_convert(convert_ctx, &buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t **)frame->data, frame->nb_samples);

                printf("pts:%10lld\t packet size:%d\n", packet->pts, packet->size);
            }
            got_picture = 0;
            av_free_packet(packet);

            swr_free(&convert_ctx);

            //=================================decode end ==========================

            memcpy(buffer, buff, sizeof(buff));

            printf("index is : %d\n", prev_index);

            //print data receive by tcp channel
            printf("fd is %d, data size:%d, got data: ", client_socket_fd, size);
            for (size_t i = 0; i < size; i++)
            {
                printf("%x", buff[i]);
            }
            printf("\n");
        }
        else if (size == 0)
        {
            printf("socket closed \n");
            close(client_socket_fd);
        }
    }
}